package com.photoeditor.demo.util.face;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.view.KeyEvent;

import com.common.base.log.DLog;
import com.google.firebase.ml.vision.common.FirebaseVisionPoint;
import com.google.firebase.ml.vision.face.FirebaseVisionFace;
import com.google.firebase.ml.vision.face.FirebaseVisionFaceContour;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.photoeditor.R;
import com.photoeditor.demo.model.bean.face.CommonFaceBean;
import com.photoeditor.demo.model.bean.face.FaceContour;
import com.photoeditor.demo.model.bean.face.FaceDetectBean;
import com.photoeditor.demo.model.bean.face.FaceDetectBeanV4;
import com.photoeditor.demo.model.bean.face.FacePoint;
import com.photoeditor.demo.model.bean.face.FaceRectBean;
import com.photoeditor.demo.model.bean.face.FaceAgingFaceBean;
import com.photoeditor.demo.model.bean.face.FaceAgingResultBean;
import com.photoeditor.demo.model.bean.SwapItemBean;
import com.photoeditor.demo.util.LanguageManager;
import com.photoeditor.demo.util.SignUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import static com.photoeditor.demo.model.face.ErrorType.RESULT_LIMIT_TIME;
import static com.photoeditor.demo.model.face.ErrorType.RESULT_MORE_FACE;
import static com.photoeditor.demo.model.face.ErrorType.RESULT_NO_FACE_CLIENT;
import static com.photoeditor.demo.model.face.ErrorType.RESULT_NO_FACE_ONLINE;
import static com.photoeditor.demo.model.face.ErrorType.RESULT_OTHER;
import static com.photoeditor.demo.model.face.ErrorType.RESULT_SUCCESS;
import static com.photoeditor.demo.model.face.FaceConstant.ACTION_EXOTIC_BLEND;
import static com.photoeditor.demo.model.face.FaceConstant.ACTION_FUTURE_BABY;
import static com.photoeditor.demo.model.face.FaceConstant.ACTION_GENDER_SWITCH;
import static com.photoeditor.demo.model.face.FaceConstant.ACTION_FACE_AGING;
import static com.photoeditor.demo.model.face.FaceConstant.ACTION_PAST_LIFE;


public class FaceUtil {

    public static final String TAG = FaceUtil.class.getSimpleName();

    public static final String BASE_URL = "http://pm.pictureme.info";//正式环境"http://139.9.221.61";

    public static final String METHOD_DETECT_FACE = "/facesecret/check";

    public static final int PARAM_RETRY_COUNT = 1;
    public static final String PARAM_CACHE_KEY_DETECT_FACE = "detect_face";

    private static final String GENDER_VALUE_MALE = "Male";
    private static final String GENDER_VALUE_FEMALE = "Female";

    public static final int DETECT_FACE_TYPE_INVALID = -1;


    public static final int DETECT_FACE_TYPE_FACE_AGING = 3;
    public static final int DETECT_FACE_TYPE_EXOTIC = 6;//换脸
    public static final int DETECT_FACE_TYPE_GENDER_SWITCH = 8;
    public static final int DETECT_FACE_TYPE_PAST_LIFE = 9;
    public static final int DETECT_FACE_TYPE_BABY_PREDICTION = 10;


    public static final int CODE_EXCEED_REQUEST_LIMIT = 3;

    public static final String METHOD_DETECT_FACE_V4 = "/ptm/checkFace";//"/facesecret/check/v4";
    public static final String METHOD_MERGE_PIC = "";
    public static final String METHOD_GENDER_SWITCH = "/ptm/transsexual/v2";//"/facesecret/transsexual";
    public static final String METHOD_PREVIOUS_LIFE = "/ptm/previousLife";//"/facesecret/previousLife";
    public static final String METHOD_GET_FACE_TEMPLATES = "";
    public static final String METHOD_BABY = "/ptm/baby";
    public static final String METHOD_GET_GENDER_SWITCH_TEMPLATES = "/ptm/transsexual/resourceTemplate";
    public static final String METHOD_GET_AGING_TEMPLATES = "/ptm/age/resourceTemplate";
    public static final String METHOD_AGING = "/ptm/age";


    public static int getDetectFaceType(String action) {
        int type = DETECT_FACE_TYPE_INVALID;
        switch (action) {

            case ACTION_FACE_AGING:
                type = DETECT_FACE_TYPE_FACE_AGING;
                break;

            case ACTION_EXOTIC_BLEND:
                type = DETECT_FACE_TYPE_EXOTIC;
                break;

            case ACTION_GENDER_SWITCH:
                type = DETECT_FACE_TYPE_GENDER_SWITCH;
                break;

            case ACTION_PAST_LIFE:
                type = DETECT_FACE_TYPE_PAST_LIFE;
                break;

            case ACTION_FUTURE_BABY:
                type = DETECT_FACE_TYPE_BABY_PREDICTION;
                break;
        }
        return type;
    }

    /**
     * 人脸检测，无缓存
     * @param imgBase64 人脸图片，转化为Base64
     * @param tag 请求的 tag, 主要用于取消对应的请求
     * @param callback 请求的回调
     */
    public static void detectFace(String imgBase64, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("pic", imgBase64);
            postData.put("type", 1);
            postData.put("flag", "1");
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_DETECT_FACE_V4;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param response
     * @param headAngle
     * @return -2-解析失败或其他错误
     *         -1-没有检测到人脸
     *         0-一张正脸
     *         1-一张侧脸
     *         2-两张脸，不管是不是侧脸
     */
    public static int parseFaceDetect(String response, double headAngle) {
        try {
            JSONObject outerJson = new JSONObject(response);//包含data
            int code = outerJson.optInt("code");
            if (code == CODE_EXCEED_REQUEST_LIMIT) {
                return -1;
            }
            if (!outerJson.optBoolean("success")) {
                return -1;
            }
            JSONObject dataJson = outerJson.optJSONObject("data");
            if (dataJson == null) {
                return -1;
            }
            JSONObject resultJson = dataJson.optJSONObject("result");
            if (resultJson == null) {
                return -1;
            }
            JSONArray facesArray = resultJson.optJSONArray("faces");
            if (facesArray == null || facesArray.isNull(0)) {
                //没有解析到人脸
                return -1;
            }
            if (facesArray.length() > 1) {
                //大于两张脸
                return facesArray.length();
            }
            if (resultJson == null) {
                return -1;
            }
            JSONObject faceJson = facesArray.optJSONObject(0);
            if (faceJson == null) {
                return -2;
            }
            JSONObject attributesJson = faceJson.optJSONObject("attributes");
            if (resultJson == null) {
                return -1;
            }
            JSONObject headposeJson = attributesJson.optJSONObject("headpose");
            if (resultJson == null) {
                return -1;
            }
            double yawAngle = headposeJson.optDouble("yaw_angle");
            DLog.d("wmgTest", "yawAndle: " + yawAngle);
            if (Math.abs(yawAngle) > Math.abs(headAngle)) {
                return 1;
            } else {
                return 0;
            }
        } catch (JSONException e) {
            e.printStackTrace();
            return -2;
        }
    }

    /**
     * 获取模板
     * @param callback 请求的回调
     */
    public static void getFaceTemplates(Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("language", LanguageManager.getLanguage());
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_GET_FACE_TEMPLATES;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 异域风情接口-实际上就是换脸接口
     * @param imgBase64
     * @param templateId
     * @param tag
     * @param callback
     */
    public static void swapFace(String imgBase64, String templateId, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("pic", imgBase64);
            postData.put("templateId", templateId);
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_MERGE_PIC;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static void requestGenderSwitchTemplates(String sex, String ethnicity, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            if (TextUtils.isEmpty(sex)) {
                postData.put("sex", "male");
            } else if (sex.toLowerCase().equals("male")) {
                postData.put("sex", "female");
            } else if (sex.toLowerCase().equals("female")) {
                postData.put("sex", "male");
            }
            postData.put("ethnicity", ethnicity);
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_GET_GENDER_SWITCH_TEMPLATES;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static void requestAgingTemplates(int sex, String ethnicity, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("age", "");
            postData.put("sex", sex);
            postData.put("ethnicity", ethnicity);
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_GET_AGING_TEMPLATES;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 性别转换接口
     * @param imgBase64
     * @param tag
     * @param callback
     */
    public static void requestGenderSwitch(String imgBase64, String templateId, String sex, String ethnicity, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("pic", imgBase64);
            postData.put("sex", sex);
            postData.put("ethnicity", ethnicity);
            postData.put("templateId", TextUtils.equals(templateId, "no_id")?"":templateId);
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_GENDER_SWITCH;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static void requestFaceAging(String imgBase64, String templateId, String age, int sex, String ethnicity, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("age", age);
            postData.put("pic", imgBase64);
            postData.put("sex", sex);
            postData.put("ethnicity", ethnicity);
            postData.put("templateId", TextUtils.equals(templateId, "no_id")?"":templateId);
            postData.put("rectangle", "");
            postData.put("key", "");
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_AGING;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 前世今生接口
     */
    public static void requestPastLife(String imgBase64, String gender, String ethnicity, Object tag, FaceBaseCallback callback) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("pic", imgBase64);
            postData.put("sex", !TextUtils.isEmpty(gender)?gender.toLowerCase():"");
            postData.put("ethnicity", !TextUtils.isEmpty(ethnicity)?ethnicity.toLowerCase():"");
            postData.put("language", "en");
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_PREVIOUS_LIFE;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 人脸检测，无缓存
     * @param imgBase64 人脸图片，转化为Base64
     * @param tag 请求的 tag, 主要用于取消对应的请求
     * @param callback 请求的回调
     * @param type 请求的类型 1 宝宝预测, 2 未来预测， 3 老化效果， 4 种族分析， 5 比美
     */
    public static void detectFace(String imgBase64, Object tag, FaceBaseCallback callback, int type) {
        try {
            JSONObject postData = new JSONObject();
            postData.put("pic", imgBase64);
            postData.put("type", type);
            SignUtils.appendSign(postData);
            String postDataStr = postData.toString();
            String url = BASE_URL + METHOD_DETECT_FACE;
            OkGo.post(url)
                    .tag(tag)
                    .retryCount(PARAM_RETRY_COUNT)
                    .cacheKey(PARAM_CACHE_KEY_DETECT_FACE)
                    .cacheMode(CacheMode.NO_CACHE)
                    .upJson(postDataStr)
                    .execute(callback);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static int parseResult(String response, int type, List list) {
        int retType = RESULT_OTHER;
        switch (type) {
            case DETECT_FACE_TYPE_FACE_AGING:
                retType = parseFaceAgingFaceBean(response, list);
                break;
            case DETECT_FACE_TYPE_EXOTIC:
            case DETECT_FACE_TYPE_GENDER_SWITCH:
            case DETECT_FACE_TYPE_PAST_LIFE:
                retType = parseFaceDetectBean(response, false, list);
                break;
        }
        return retType;
    }

    public static void showExitDialogByResult(Context context, int retType,
                                              final DialogInterface.OnClickListener cancel,
                                              final DialogInterface.OnClickListener retry,
                                              ExitDialogListener dlgListener) {
        switch (retType) {
            case RESULT_LIMIT_TIME:
                showExitDialog(context, context.getString(R.string.net_connect_error), cancel, retry, dlgListener);
                break;
            case RESULT_MORE_FACE:
            case RESULT_NO_FACE_ONLINE:
                showExitDialog(context, context.getString(R.string.detect_face_error), cancel, retry, dlgListener);
                break;
            case RESULT_NO_FACE_CLIENT:
                showExitDialog(context, context.getString(R.string.detect_face_error_client), cancel, retry, dlgListener);
                break;
            case RESULT_OTHER:
                showExitDialog(context, context.getString(R.string.net_connect_error), cancel, retry, dlgListener);
                break;
        }
    }

    public static FaceAgingResultBean parseFaceAgingFaceDetectBean2ResultBean(FaceAgingFaceBean faceBean, String imgBase64) {
        FaceAgingResultBean bean = new FaceAgingResultBean();
        bean.ethnicity = faceBean.getEthnicity();
        bean.key = faceBean.getKey();
        if (faceBean.getGender() == null || faceBean.getGender().equals("")) {
            bean.sex = 0;
        } else {
            bean.sex = faceBean.getGender().equals(GENDER_VALUE_MALE) ? 0 : 1;
        }
        if (imgBase64 != null && !imgBase64.equals("")) {
            bean.pic = imgBase64;
        }
        bean.rectangle = faceBean.getRectangle();
        return bean;
    }

    /**
     * 调用离开弹窗
     * @param context
     * @param content  弹窗消息内容
     * @param cancel  点击回调
     * @param dlgListener 弹窗回调
     */
    public static void showExitDialog(Context context, String content,
                                      final DialogInterface.OnClickListener cancel,
                                      final DialogInterface.OnClickListener retry,
                                      ExitDialogListener dlgListener) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context)
                .setTitle(context.getString(R.string.error_dialog_title))
                .setMessage(content)
                .setCancelable(false)
                .setOnKeyListener(new DialogInterface.OnKeyListener() {
                    @Override
                    public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && cancel != null) {
                            cancel.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
                            return true;
                        }
                        return false;
                    }
                });
        if (cancel != null) {
            builder.setPositiveButton(R.string.error_dialog_button_cancel, cancel);
        }
        if (retry != null) {
            builder.setNegativeButton(R.string.error_dialog_button_retry, retry);
        }
        Dialog dlg = builder.create();
        try {
            dlg.show();
            if (dlgListener != null) {
                dlgListener.onExitDialogShow();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static int parseFaceAgingFaceBean(String response, List list) {
        try {
            JSONObject outerJson = new JSONObject(response);
            int code = outerJson.optInt("code");
            if (code == CODE_EXCEED_REQUEST_LIMIT) {
                return RESULT_LIMIT_TIME;
            }
            if (!outerJson.optBoolean("success")) {
                return RESULT_OTHER;
            }
            JSONObject dataJson = outerJson.optJSONObject("data");
            if (dataJson == null) {
                return RESULT_OTHER;
            }
            JSONObject resultJson = dataJson.optJSONObject("result");//包含image_id和faces数组
            JSONArray faces = resultJson.getJSONArray("faces");
            if (faces.length() == 0 || faces.get(0) == null) {
                return RESULT_NO_FACE_ONLINE;
            }
            if (faces.length() != 1) {
                return RESULT_MORE_FACE;
            }
            for (int i = 0; i < faces.length(); i++) {
                JSONObject face = faces.optJSONObject(i);
                JSONObject attriJson = face.optJSONObject("attributes");
                JSONObject rectJson = face.optJSONObject("face_rectangle");
                JSONObject landMark = face.optJSONObject("landmark");
                if (landMark == null) {
                    return RESULT_NO_FACE_ONLINE;
                }
                FaceAgingFaceBean bean = new FaceAgingFaceBean();
                bean.setCode(code);
                JSONObject genderJson = attriJson.optJSONObject("gender");
                JSONObject ethnicJson = attriJson.optJSONObject("ethnicity");
                bean.setGender(genderJson.optString("value"));
                bean.setEthnicity(ethnicJson.optString("value"));
                bean.setKey(dataJson.optString("key"));
                bean.setRequestId(resultJson.optString("request_id"));
                bean.setLeft(rectJson.optInt("left"));
                bean.setTop(rectJson.optInt("top"));
                bean.setWidth(rectJson.optInt("width"));
                bean.setHeight(rectJson.optInt("height"));
                StringBuilder sb = new StringBuilder();
                sb.append(bean.getTop()).append(",").append(bean.getLeft()).append(",")
                        .append(bean.getWidth()).append(",").append(bean.getHeight());
                bean.setRectangle(sb.toString());
                bean.setFaceContour(new FaceContour());
                parseFaceContour(bean.getFaceContour(), landMark);
                parseEyeContour(bean.getFaceContour(), landMark);
                parseEyebrowContour(bean.getFaceContour(), landMark);
                parseNoseContour(bean.getFaceContour(), landMark);
                parseMouthContour(bean.getFaceContour(), landMark);
                list.add(bean);
            }
        } catch (JSONException e) {
            e.printStackTrace();
            return RESULT_OTHER;
        }
        if (list.size() == 0) {
            return RESULT_NO_FACE_ONLINE;
        }
        if (list.size() != 1) {
            return RESULT_MORE_FACE;
        }
        return RESULT_SUCCESS;
    }

    private static void parseMouthContour(FaceContour faceContour, JSONObject landMark) {
        JSONObject jsonObject = landMark.optJSONObject("mouth_left_corner");
        Point p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthLeft = p;

        jsonObject = landMark.optJSONObject("mouth_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthRight = p;

        jsonObject = landMark.optJSONObject("mouth_upper_lip_top");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthUpLipTop = p;

        jsonObject = landMark.optJSONObject("mouth_upper_lip_bottom");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthUpLipBottom = p;

        jsonObject = landMark.optJSONObject("mouth_lower_lip_top");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthLowLipTop = p;

        jsonObject = landMark.optJSONObject("mouth_lower_lip_bottom");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.mouthLowLipBottom = p;

        //解析上嘴唇左轮廓
        List<Point> upLipLeftPts = new ArrayList<>();
        for (int i = 1; i <= 4; i++) {
            String contour = new StringBuilder().append("mouth_upper_lip_left_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            upLipLeftPts.add(p);
        }
        faceContour.mouthUpLipLeftContour = upLipLeftPts;

        //解析上嘴唇右轮廓
        List<Point> upLipRightPts = new ArrayList<>();
        for (int i = 1; i <= 4; i++) {
            String contour = new StringBuilder().append("mouth_upper_lip_right_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            upLipRightPts.add(p);
        }
        faceContour.mouthUpLipRightContour = upLipRightPts;

        //解析下嘴唇左轮廓
        List<Point> bottomLipLeftPts = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            String contour = new StringBuilder().append("mouth_lower_lip_left_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            bottomLipLeftPts.add(p);
        }
        faceContour.mouthLowLipLeftContour = bottomLipLeftPts;

        //解析下嘴唇左轮廓
        List<Point> bottomLipRightPts = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            String contour = new StringBuilder().append("mouth_lower_lip_right_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            bottomLipRightPts.add(p);
        }
        faceContour.mouthLowLipRightContour = bottomLipRightPts;
    }

    private static void parseNoseContour(FaceContour faceContour, JSONObject landMark) {
        //解析鼻尖点
        JSONObject jsonObject = landMark.optJSONObject("nose_tip");
        Point p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.noseTip = p;

        //解析鼻子底部中点
        jsonObject = landMark.optJSONObject("nose_middle_contour");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        faceContour.noseMiddle = p;

        //解析鼻梁点
        List<Point> noseBridge = new ArrayList<>();
        jsonObject = landMark.optJSONObject("nose_bridge1");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        noseBridge.add(p);

        jsonObject = landMark.optJSONObject("nose_bridge2");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        noseBridge.add(p);

        jsonObject = landMark.optJSONObject("nose_bridge3");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        noseBridge.add(p);
        faceContour.noseBridgeContour = noseBridge;

        //解析鼻子左边轮廓点
        List<Point> noseLeftPts = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            String contour = new StringBuilder().append("nose_left_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            noseLeftPts.add(p);
        }
        faceContour.noseLeftContour = noseLeftPts;

        //解析鼻子右边轮廓点
        List<Point> noseRightPts = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            String contour = new StringBuilder().append("nose_right_contour").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            jsonObject = landMark.optJSONObject(contour);
            p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
            noseRightPts.add(p);
        }
        faceContour.noseRightContour = noseRightPts;
    }

    private static void parseEyebrowContour(FaceContour faceContour, JSONObject landMark) {
        //解析左眉轮廓点
        List<Point> leftEyebrowPts = new ArrayList<>();
        JSONObject jsonObject = landMark.optJSONObject("left_eyebrow_left_corner");
        Point p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_upper_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_upper_middle");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_upper_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_upper_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_lower_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_lower_middle");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_lower_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("left_eyebrow_lower_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyebrowPts.add(p);

        faceContour.leftEyebrowContour = leftEyebrowPts;

        //解析右眉轮廓点
        List<Point> rightEyebrowPts = new ArrayList<>();
        jsonObject = landMark.optJSONObject("right_eyebrow_upper_left_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_upper_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_upper_middle");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_upper_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_lower_left_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_lower_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_lower_middle");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        jsonObject = landMark.optJSONObject("right_eyebrow_lower_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyebrowPts.add(p);

        faceContour.rightEyebrowContour = rightEyebrowPts;
    }

    private static void parseEyeContour(FaceContour faceContour, JSONObject landMark) {
        //解析左眼轮廓点
        List<Point> leftEyePts = new ArrayList<>();
        JSONObject jsonObject = landMark.optJSONObject("left_eye_left_corner");
        Point p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_upper_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_top");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_upper_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_lower_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_bottom");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_lower_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_pupil");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        jsonObject = landMark.optJSONObject("left_eye_center");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        leftEyePts.add(p);

        faceContour.leftEyeContour = leftEyePts;

        //解析右眼轮廓点
        List<Point> rightEyePts = new ArrayList<>();
        jsonObject = landMark.optJSONObject("right_eye_left_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_upper_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_top");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_upper_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_right_corner");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_lower_right_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_bottom");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_lower_left_quarter");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_pupil");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        jsonObject = landMark.optJSONObject("right_eye_center");
        p = new Point(jsonObject.optInt("x"), jsonObject.optInt("y"));
        rightEyePts.add(p);

        faceContour.rightEyeContour = rightEyePts;
    }

    private static void parseFaceContour(FaceContour faceContour, JSONObject landMark) {
        //解析下巴关键点
        JSONObject faceChinJson = landMark.optJSONObject("contour_chin");
        Point p = new Point(faceChinJson.optInt("x"), faceChinJson.optInt("y"));
        faceContour.faceChin = p;

        //解析左侧人脸关键点
        List<Point> leftContourPts = new ArrayList<>();
        JSONObject leftConJson = null;
        for (int i = 1; i <= 16; i++) {
            String contour = new StringBuilder().append("contour_left").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            leftConJson = landMark.optJSONObject(contour);
            p = new Point(leftConJson.optInt("x"), leftConJson.optInt("y"));
            leftContourPts.add(p);
        }
        faceContour.leftFaceContour = leftContourPts;

        //解析右侧人脸关键点
        List<Point> rightContourPts = new ArrayList<>();
        JSONObject rightConJson = null;
        for (int i = 1; i <= 16; i++) {
            String contour = new StringBuilder().append("contour_right").append(i).toString();
            DLog.d(TAG, "parse " + contour);
            rightConJson = landMark.optJSONObject(contour);
            p = new Point(rightConJson.optInt("x"), rightConJson.optInt("y"));
            rightContourPts.add(p);
        }
        faceContour.rightFaceContour = rightContourPts;
    }

    public static int parseFaceTemplateBean(String response, List<SwapItemBean> list, String gender) {
        try {
            JSONObject outerJson = new JSONObject(response);
            int code = outerJson.optInt("code");
            if (code == CODE_EXCEED_REQUEST_LIMIT) {
                return RESULT_LIMIT_TIME;
            }
            if (!outerJson.optBoolean("success")) {
                return RESULT_OTHER;
            }
            JSONObject dataJson = outerJson.optJSONObject("data");
            if (dataJson == null) {
                return RESULT_OTHER;
            }
            JSONArray templateArray = dataJson.getJSONArray("templates");
            if (templateArray == null || templateArray.length() < 1) {
                return RESULT_OTHER;
            }
            for (int i = 0; i < templateArray.length(); i++) {
                JSONObject template = (JSONObject) templateArray.get(i);
                if (!TextUtils.isEmpty(gender)) {
                    if (template != null && TextUtils.equals(template.optString("gender").toLowerCase(), gender.toLowerCase())) {
                        SwapItemBean bean = new SwapItemBean();
                        bean.setUrl(template.optString("url"));
                        bean.setName(template.optString("name"));
                        bean.setTemplateId(template.optString("templateId"));
                        bean.setGender(template.optString("gender"));
                        list.add(bean);
                    }
                } else {
                    SwapItemBean bean = new SwapItemBean();
                    bean.setUrl(template.optString("url"));
                    bean.setName(template.optString("name"));
                    bean.setTemplateId(template.optString("templateId"));
                    bean.setGender(template.optString("gender"));
                    list.add(bean);
                }
            }
            return RESULT_SUCCESS;
        } catch (JSONException e) {
            e.printStackTrace();
            return RESULT_OTHER;
        }
    }

    private static int parseFaceDetectBean(String response, boolean isTwoImage, List list) {
        try {
            JSONObject outerJson = new JSONObject(response);
            int code = outerJson.optInt("code");
            if (code == CODE_EXCEED_REQUEST_LIMIT) {
                return RESULT_LIMIT_TIME;
            }
            if (!outerJson.optBoolean("success")) {
                return RESULT_OTHER;
            }
            JSONObject dataJson = outerJson.optJSONObject("data");
            if (dataJson == null) {
                return RESULT_OTHER;
            }
            JSONObject resultJson = dataJson.optJSONObject("result");
            JSONArray faceArray = null;
            //这里为了区分人脸检测v4的结果，faceType为0代表旧的检测结果数据类型
            int faceType = 0;
            if (resultJson.has("faces")) {
                faceType = 1;
                faceArray = resultJson.getJSONArray("faces");
            } else {
                faceArray = resultJson.getJSONArray("face");
            }
            if (faceArray.length() == 0 || faceArray.get(0) == null) {
                return RESULT_NO_FACE_ONLINE;
            }
            if (isTwoImage && faceArray.length() != 2) {//两张照片，人脸不够
                return RESULT_NO_FACE_ONLINE;
            }
            if (!isTwoImage && faceArray.length() != 1) {//只需一张人脸，但人脸数不对
                return RESULT_MORE_FACE;
            }
            for (int i = 0; i < faceArray.length(); i++) {
                if (faceType == 0) {
                    FaceDetectBean bean = new FaceDetectBean();
                    bean.setCode(code);
                    JSONObject face = (JSONObject) faceArray.get(i);
                    bean.setKey(dataJson.optString("key"));
                    bean.setTwoImage(isTwoImage);
                    bean.setImageWidth(resultJson.optInt("image_width"));
                    bean.setImageHeight(resultJson.optInt("image_height"));
                    bean.setExpression(face.optInt("expression"));
                    bean.setGender(face.optInt("gender"));
                    bean.setBeauty(face.optInt("beauty"));
                    bean.setRoll(face.optInt("roll"));
                    bean.setYaw(face.optInt("yaw"));
                    bean.setGlasses(face.optInt("glasses"));
                    bean.setFaceId(face.optLong("face_id"));
                    bean.setHat(face.optInt("hat"));
                    bean.setPitch(face.optInt("pitch"));
                    bean.setAge(face.optInt("age"));
                    bean.setMask(face.optInt("mask"));
                    bean.setX(face.optInt("x"));
                    bean.setY(face.optInt("y"));
                    bean.setWidth(face.optInt("width"));
                    bean.setHeight(face.optInt("height"));

                    JSONObject faceShape = face.optJSONObject("face_shape");
                    if (faceShape == null) {
                        return RESULT_NO_FACE_ONLINE;
                    }
                    bean.setRightEye(getPoints(faceShape.getJSONArray("right_eye")));
                    bean.setLeftEye(getPoints(faceShape.getJSONArray("left_eye")));
                    bean.setRightEyebrow(getPoints(faceShape.getJSONArray("right_eyebrow")));
                    bean.setLeftEyebrow(getPoints(faceShape.getJSONArray("left_eyebrow")));
                    bean.setNose(getPoints(faceShape.getJSONArray("nose")));
                    bean.setFaceProfile(getPoints(faceShape.getJSONArray("face_profile")));
                    bean.setMouth(getPoints(faceShape.getJSONArray("mouth")));
                    bean.setPupil(getPoints(faceShape.getJSONArray("pupil")));

                    list.add(bean);
                } else {
                    FaceDetectBeanV4 bean = new FaceDetectBeanV4();
                    bean.code = code;
                    JSONObject face = (JSONObject) faceArray.get(i);

                    JSONObject attributes = face.getJSONObject("attributes");
                    if (attributes != null) {
                        JSONObject gender = attributes.getJSONObject("gender");
                        if (gender != null) {
                            String genderStr = (String) gender.get("value");
                            if(!TextUtils.isEmpty(genderStr)) {
                                bean.setGender(genderStr);
                            }
                        }
                        String ethnicityStr = attributes.getString("ethnicity");
                        if (!TextUtils.isEmpty(ethnicityStr)) {
                            if (ethnicityStr.contains("value")) {
                                JSONObject ethnicity = attributes.getJSONObject("ethnicity");
                                if (ethnicity != null) {
                                    ethnicityStr = (String) ethnicity.get("value");
                                    if (!TextUtils.isEmpty(ethnicityStr)) {
                                        bean.setEthnicity(ethnicityStr);
                                    }
                                }
                            } else {
                                bean.setEthnicity(ethnicityStr);
                            }
                        }

                    }

                    JSONObject landmark = face.getJSONObject("landmark");

                    FaceContour contour = new FaceContour();
                    parseFaceContour(contour, landmark);
                    parseEyeContour(contour, landmark);
                    parseEyebrowContour(contour, landmark);
                    parseNoseContour(contour, landmark);
                    parseMouthContour(contour, landmark);
                    bean.setLandMark(contour);

                    list.add(bean);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
            return RESULT_OTHER;
        }
        if (isTwoImage && list.size() != 2) {
            return RESULT_NO_FACE_ONLINE;
        }
        if (!isTwoImage && list.size() == 0 ) {
            return RESULT_NO_FACE_ONLINE;
        }
        if (!isTwoImage && list.size() != 1 ) {
            return RESULT_MORE_FACE;
        }
        return RESULT_SUCCESS;
    }

    public static int parceFacesDetectBean(String response, List list) {
        try {
            JSONObject outerJson = new JSONObject(response);
            int code = outerJson.optInt("code");
            if (code == CODE_EXCEED_REQUEST_LIMIT) {
                return RESULT_LIMIT_TIME;
            }
            if (!outerJson.optBoolean("success")) {
                return RESULT_OTHER;
            }
            JSONArray dataJson = outerJson.optJSONArray("data");
            if (dataJson == null || dataJson.length() < 1) {
                return RESULT_OTHER;
            }
            int length = dataJson.length();
            for (int i=0; i<length; i++) {
                JSONObject data = (JSONObject) dataJson.get(i);
                if (data != null && data.has("age") && data.has("gender") && data.has("face")) {
                    FaceRectBean bean = new FaceRectBean();
                    bean.setAge(data.getInt("age"));
                    bean.setGender(data.getString("gender"));
                    JSONObject face = data.getJSONObject("face");
                    if (face != null) {
                        bean.setLeft(face.getInt("left"));
                        bean.setTop(face.getInt("top"));
                        bean.setWidth(face.getInt("width"));
                        bean.setHeight(face.getInt("height"));
                    }
                    list.add(bean);
                }
            }
            return RESULT_SUCCESS;
        } catch (Exception e) {
            return RESULT_OTHER;
        }
    }

    public static int getCommonFaceEyeLineAngle(CommonFaceBean bean) {
        FacePoint leftEyeLeftEnd = bean.leftEye.get(0);
        FacePoint rightEyeRightEnd = bean.rightEye.get(8);
        float dy = rightEyeRightEnd.y - leftEyeLeftEnd.y;
        float dx = rightEyeRightEnd.x - leftEyeLeftEnd.x;
        return getRotationByLine(dx, dy);
    }

    /**
     * 根据右眼中心与左眼中心的连线，判断照片是否旋转
     * dy、dx必须由右眼位置减去左眼位置得到
     * @param dx
     * @param dy
     * @return 0，不旋转；90，顺时针旋转了90度；180，顺时针旋转了180度；270，顺时针旋转了270度；
     */
    private static int getRotationByLine(float dx, float dy) {
        if (dy == 0 && dx > 0) {
            return 0;
        } else if (dx == 0 && dy > 0) {
            return 90;
        } else if (dy == 0 && dx < 0) {
            return 180;
        } else if (dx == 0 && dy < 0) {
            return 270;
        }
        int angle = 0;
        double angleRadian = 0;
        if (dy > 0 && dx > 0) {
            angleRadian = Math.atan(dy / dx);
            angle = (int) (180 * angleRadian / Math.PI);
            if (angle < 45) {
                return 0;
            } else {
                return 90;
            }
        } else if (dy > 0 && dx < 0) {
            angleRadian = Math.atan(dy / -dx);
            angle = 90 - (int) (180 * angleRadian / Math.PI);
            if (angle < 45) {
                return 90;
            } else {
                return 180;
            }
        } else if (dy < 0 && dx < 0) {
            angleRadian = Math.atan(-dy / -dx);
            angle = (int) (180 * angleRadian / Math.PI);
            if (angle < 45) {
                return 180;
            } else {
                return 270;
            }
        } else if (dy < 0 && dx > 0) {
            angleRadian = Math.atan(-dy / dx);
            angle = 90 - (int) (180 * angleRadian / Math.PI);
            if (angle < 45) {
                return 270;
            } else {
                return 0;
            }
        }
        return 0;
    }

    private static List<Point> getPoints(JSONArray array) throws JSONException {
        List<Point> result = new ArrayList<>();
        for (int i = 0; i < array.length(); i++) {
            JSONObject ptJson = array.optJSONObject(i);
            Point point = new Point();
            point.x = ptJson.optInt("x");
            point.y = ptJson.optInt("y");
            result.add(point);
        }
        return result;
    }

    public static CommonFaceBean parseCommonFaceBean(FirebaseVisionFace face, float scaleX, float scaleY) {
        CommonFaceBean bean = new CommonFaceBean();
        bean.faceOval = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.FACE).getPoints(), scaleX, scaleY);
        bean.leftEyeBrowTop = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.LEFT_EYEBROW_TOP).getPoints(), scaleX, scaleY);
        bean.leftEyeBrowBottom = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.LEFT_EYEBROW_BOTTOM).getPoints(), scaleX, scaleY);
        bean.rightEyeBrowTop = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.RIGHT_EYEBROW_TOP).getPoints(), scaleX, scaleY);
        bean.rightEyeBrowBottom = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.RIGHT_EYEBROW_BOTTOM).getPoints(), scaleX, scaleY);
        bean.leftEye = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.LEFT_EYE).getPoints(), scaleX, scaleY);
        bean.rightEye = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.RIGHT_EYE).getPoints(), scaleX, scaleY);
        bean.upperLipTop = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.UPPER_LIP_TOP).getPoints(), scaleX, scaleY);
        bean.upperLipBottom = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.UPPER_LIP_BOTTOM).getPoints(), scaleX, scaleY);
        bean.lowLipTop = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.LOWER_LIP_TOP).getPoints(), scaleX, scaleY);
        bean.lowLipBottom = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.LOWER_LIP_BOTTOM).getPoints(), scaleX, scaleY);
        bean.noseBridge = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.NOSE_BRIDGE).getPoints(), scaleX, scaleY);
        bean.noseBottom = processCommonFacePoints(face.getContour(FirebaseVisionFaceContour.NOSE_BOTTOM).getPoints(), scaleX, scaleY);
        return bean;
    }

    private static List<FacePoint> processCommonFacePoints(List<FirebaseVisionPoint> pts) {
        List<FacePoint> ret = new ArrayList<>();
        for (FirebaseVisionPoint p : pts)
            ret.add(new FacePoint(p.getX() != null ? p.getX() : 0,
                    p.getY() != null ? p.getY() : 0,
                    p.getZ() != null ? p.getZ() : 0));
        return ret;
    }

    private static List<FacePoint> processCommonFacePoints(List<FirebaseVisionPoint> pts, float scaleX, float scaleY) {
        List<FacePoint> ret = new ArrayList<>();
        for (FirebaseVisionPoint p : pts)
            ret.add(new FacePoint(p.getX() != null ? p.getX() * scaleX : 0,
                    p.getY() != null ? p.getY() * scaleY : 0,
                    p.getZ() != null ? p.getZ() : 0));
        return ret;
    }

    public interface ExitDialogListener {
        public void onExitDialogShow();
    }
}
